package cn.com.generaldata.os.service.indicator_evaluation;

import java.math.BigDecimal;
import java.util.List;

import org.nutz.castor.Castors;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Record;
import org.nutz.dao.impl.sql.SqlTemplate;
import org.nutz.dao.sql.Criteria;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.random.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.generaldata.jsme_indicator_system.entity.IndicatorAccounting;
import cn.com.generaldata.jsme_indicator_system.entity.IndicatorEvaluation;
import cn.com.generaldata.jsme_indicator_system.entity.IndicatorInput;
import cn.com.generaldata.jsme_indicator_system.util.Constants;
import cn.com.generaldata.os.pojo.IndicatorEvaluationResult;
import cn.com.generaldata.os.service.indicator_constant.ProvinceIndicatorConstant;
import cn.com.generaldata.os.util.BeanMapper;
import cn.com.generaldata.os.vo.IndicatorAccountVO;

/**
 * 评估指标公式运行处理基类
 */
public abstract class IndicatorEvaluationCalculateService implements CalculateService {

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	protected Dao dao;

	protected Dao indicatorSystemDao;

	/**
	 * 计算评估指标，根据每个公式的定义，由各自的子类实现公式的计算过程
	 */
	protected abstract Double calculate(IndicatorEvaluation indicator, IndicatorAccountVO indicatorAccountVO);

	@Override
	public void calculateIndicator(IndicatorEvaluation indicator, IndicatorAccountVO indicatorAccountVO) {
		Double result = calculate(indicator, indicatorAccountVO);
		if (result == null || Double.isNaN(result) || Double.isInfinite(result)) {
			throw Lang.makeThrow("评估计算类返回结果为非正常数值,计算类信息：%s,计算条件：%s,计算结果:%s", Json.toJson(indicator),
					Json.toJson(indicatorAccountVO), result);
		}
		result = new BigDecimal(result).setScale(10, BigDecimal.ROUND_HALF_UP).doubleValue();
		IndicatorEvaluationResult ier = createIndicatorEvaluationResult(indicator, indicatorAccountVO);
		ier.setIndicatorValue(result);
		Criteria cri = getIndicatorAccountingDataCri(indicator, indicatorAccountVO);

		Record record = dao.fetch("tbl_indicator_evaluation_res", cri);
		if (record != null) {
			dao.clear("tbl_indicator_evaluation_res", cri);
		}

		saveIndicatorEvaluationResult(ier);
	}

	protected void saveIndicatorEvaluationResult(IndicatorEvaluationResult ier) {
		// 保存新记录
		Chain chain = Chain.make("id", R.UU16());
		chain.add("indicator_id", ier.getIndicatorId());
		chain.add("area_id", ier.getAreaId());
		chain.add("time_type", ier.getTimeType());
		chain.add("year", ier.getYear());
		if (ier.getTimeType() == Constants.REPORT_TIME_MONTH) {
			chain.add("month", ier.getMonth());
		} else if (ier.getTimeType() == Constants.REPORT_TIME_YEAR) {
			chain.add("year_time", ier.getYearTime());
		} else {
			chain.add("quarter", ier.getQuarter());
		}

		chain.add("indicator_value", ier.getIndicatorValue());

		dao.insert("tbl_indicator_evaluation_res", chain);
	}

	protected IndicatorEvaluationResult createIndicatorEvaluationResult(IndicatorEvaluation indicator,
			IndicatorAccountVO indicatorAccountVO) {
		IndicatorEvaluationResult result = BeanMapper.map(indicatorAccountVO, IndicatorEvaluationResult.class);
		result.setIndicatorId(indicator.getId());
		return result;
	}

	protected Criteria getIndicatorAccountingDataCri(IndicatorEvaluation indicator,
			IndicatorAccountVO indicatorAccountVO) {
		Criteria cri = Cnd.cri();
		cri.where().and("indicator_id", "=", indicator.getId());
		cri.where().and("time_type", "=", indicatorAccountVO.getTimeType());
		cri.where().and("year", "=", indicatorAccountVO.getYear());
		cri.where().and("area_id", "=", indicatorAccountVO.getAreaId());
		if (indicatorAccountVO.getTimeType().intValue() == Constants.REPORT_TIME_MONTH) {
			cri.where().and("month", "=", indicatorAccountVO.getMonth());
		} else if (indicatorAccountVO.getTimeType() == Constants.REPORT_TIME_YEAR) {
			cri.where().and("year_time", "=", indicatorAccountVO.getYearTime());
		} else {
			cri.where().and("quarter", "=", indicatorAccountVO.getQuarter());
		}
		return cri;
	}

	@Override
	public void setDao(Dao dao) {
		this.dao = dao;
	}

	@Override
	public void setIndicatorSystemDao(Dao indicatorSystemDao) {
		this.indicatorSystemDao = indicatorSystemDao;
	}

	@Override
	public void setCalculateServiceHelper(CalculateServiceHelper calculateServiceHelper) {
	}

	/**
	 * 获取录入指标id
	 * 
	 * @param name 指标名称
	 * @param category 指标分类
	 * @return
	 */

	protected Integer getIndicatorInputId(String name, Integer category) {
		Cnd cnd = Cnd.where("name", "=", name);
		if (category != null) {
			cnd.and("category", "=", category);
		}
		List<IndicatorInput> indicators = indicatorSystemDao.query(IndicatorInput.class, cnd);
		Integer indicatorInputId = null;
		if (!indicators.isEmpty()) {
			indicatorInputId = indicators.get(0).getId();
		}
		return indicatorInputId;

	}

	/**
	 * 获取评估指标id
	 * 
	 * @param name 指标名称
	 * @param category 指标分类
	 * @return
	 */
	protected Integer getIndicatorEvaluationId(String name, String areaId) {
		Cnd cnd = Cnd.where("name", "=", name);
		if (areaId != null) {
			Integer level = getIndicatorEvaluationLevel(areaId);
			cnd.and("section", "=", level);
		}
		List<IndicatorEvaluation> indicators = indicatorSystemDao.query(IndicatorEvaluation.class, cnd);
		Integer indicatorInputId = null;
		if (!indicators.isEmpty()) {
			indicatorInputId = indicators.get(0).getId();
		}
		return indicatorInputId;

	}

	/**
	 * 获取评估指标对应的区域.
	 * 
	 * @param areaId
	 * @return
	 */
	private Integer getIndicatorEvaluationLevel(String areaId) {
		if (ProvinceIndicatorConstant.NATION_AREA_ID.equals(areaId)) {
			return Constants.INDICATOR_LEVEL_NATION;
		}
		if (areaId.matches("\\d*0{13}$")) {
			return Constants.INDICATOR_LEVEL_PROVINCE;
		} else if (areaId.matches("\\d*0{11}$")) {
			return Constants.INDICATOR_LEVEL_CITY;
		} else {
			return Constants.INDICATOR_LEVEL_COUNTY;
		}
	}

	/**
	 * 获取核算指标id
	 * 
	 * @param name 指标名称
	 * @param category 指标分类
	 * @return
	 */
	protected Integer getIndicatorAccountingId(String name, Integer... level) {
		Cnd cnd = Cnd.where("name", "=", name);
		if (level != null && level.length > 0) {
			cnd.and("section", "IN", level);
		}
		List<IndicatorAccounting> indicators = indicatorSystemDao.query(IndicatorAccounting.class, cnd);
		Integer indicatorInputId = null;
		if (!indicators.isEmpty()) {
			indicatorInputId = indicators.get(0).getId();
		}
		return indicatorInputId;

	}

	protected Criteria getIndicatorDataCri(IndicatorAccountVO indicatorAccountVO, int year, int indicatorId) {
		Criteria cri = Cnd.cri();
		cri.where().and("time_type", "=", Constants.REPORT_TIME_YEAR);
		cri.where().and("year", "=", year);
		cri.where().and("year_time", "=", 2);
		cri.where().and("area_id", "=", indicatorAccountVO.getAreaId());
		cri.where().and("indicator_id", "=", indicatorId);
		return cri;
	}

	/**
	 * 获取相应指标的指标值
	 * 
	 * @param tableName 表名
	 * @param cri 查询条件
	 * @param indicatorValueColumnName 指标值对应的列名
	 * @return
	 */
	private Double getIndicatorValue(String tableName, Criteria cri, String indicatorValueColumnName) {
		try {
			Record record = dao.fetch(tableName, cri);

			Double result = null;
			if (record == null) {
				// throw Lang.makeThrow("引用的指标值不存在，无法进行指标的运算,查询表名:%s,查询条件:%s", tableName, cri.toString());
				return null;
			} else {
				result = Castors.me().castTo(record.get(indicatorValueColumnName), Double.class);
			}
			return result;
		} catch (Exception e) {
			throw Lang.wrapThrow(e);
		}
	}

	/**
	 * 获取录入指标的指标值
	 * 
	 * @param cri
	 * @return
	 */
	protected Double getInputIndicatorValue(Criteria cri) {
		return getIndicatorValue("tbl_indicator_data", cri, "indicator_value");
	}

	/**
	 * 获取核算指标的指标值
	 * 
	 * @param cri
	 * @return
	 */
	protected Double getAccountingIndicatorValue(Criteria cri) {
		return getIndicatorValue("tbl_indicator_account", cri, "edit_value");
	}

	/**
	 * 获取评估指标的指标值
	 * 
	 * @param cri
	 * @return
	 */
	protected Double getEvaluationIndicatorValue(Criteria cri) {
		return getIndicatorValue("tbl_indicator_evaluation_res", cri, "indicator_value");
	}

	/**
	 * 获取录入指标或核算指标的指标值，优先从录入指标取值
	 * 
	 * @param indicatorAccountVO
	 * @param indicatorName
	 * @return
	 */
	protected Double getInputOrAccountingIndicatorValue(IndicatorAccountVO indicatorAccountVO, int year,
			String indicatorName) {
		Double result = null;
		Integer indicatorInputId = getIndicatorInputId(indicatorName, null);

		if (indicatorInputId != null) {
			// 查询数据
			Criteria inputCri = getIndicatorDataCri(indicatorAccountVO, year, indicatorInputId);
			result = getInputIndicatorValue(inputCri);
			// 数据为空，在查核算表
			if (result == null) {
				Integer[] indicatorAccountingLevel = getIndicatorAccountingLevelByAreaId(indicatorAccountVO.getAreaId());
				Integer indicatorAccountingId = getIndicatorAccountingId(indicatorName, indicatorAccountingLevel);
				if (indicatorAccountingId != null) {
					Criteria accountingCri = getIndicatorDataCri(indicatorAccountVO, year, indicatorAccountingId);
					result = getAccountingIndicatorValue(accountingCri);
				}
			}

		} else {
			Integer[] indicatorAccountingLevel = getIndicatorAccountingLevelByAreaId(indicatorAccountVO.getAreaId());
			Integer indicatorAccountingId = getIndicatorAccountingId(indicatorName, indicatorAccountingLevel);
			if (indicatorAccountingId != null) {
				Criteria accountingCri = getIndicatorDataCri(indicatorAccountVO, year, indicatorAccountingId);
				result = getAccountingIndicatorValue(accountingCri);
			}

		}
		return result;
	}

	/**
	 * 根据查询指标id，获取结果最大年份.
	 * 
	 * @param indicatorId
	 * @return
	 */
	protected Integer getInputOrAccountingMaxYear(String indicatorName, String areaId) {
		Integer result = null;
		Integer indicatorInputId = getIndicatorInputId(indicatorName, null);
		SqlTemplate sqlTemplate = new SqlTemplate(dao);

		if (indicatorInputId != null) {
			String sql = "select max(year) from tbl_indicator_data where indicator_id='" + indicatorInputId + "'";
			result = sqlTemplate.queryForInt(sql, null);

			// 数据为空，在查核算表
			if (result == null) {
				Integer[] levels = getIndicatorAccountingLevelByAreaId(areaId);
				Integer indicatorAccountingId = getIndicatorAccountingId(indicatorName, levels);
				if (indicatorAccountingId != null) {
					String sql2 = "select max(year) from tbl_indicator_account where indicator_id='" + indicatorInputId
							+ "'";
					result = sqlTemplate.queryForInt(sql2, null);
				}
			}

		} else {
			Integer indicatorAccountingId = getIndicatorAccountingId(indicatorName, null);
			if (indicatorAccountingId != null) {
				String sql = "select max(year) from tbl_indicator_account where indicator_id='" + indicatorInputId
						+ "'";
				result = sqlTemplate.queryForInt(sql, null);
			}
		}
		return result;
	}

	protected Integer getEvaluationMaxYear(String indicatorName, String areaId) {
		Integer result = null;
		SqlTemplate sqlTemplate = new SqlTemplate(dao);
		Integer indicatorEvaluationId = getIndicatorEvaluationId(indicatorName, areaId);
		if (indicatorEvaluationId != null) {
			String sql = "select max(year) from tbl_indicator_evaluation_res where indicator_id='"
					+ indicatorEvaluationId + "'";
			result = sqlTemplate.queryForInt(sql, null);
		}
		return result;
	}

	/**
	 * 根据查询地区id，获取核算指标的区域属性.
	 * 
	 * @param areaId
	 * @return
	 */
	private Integer[] getIndicatorAccountingLevelByAreaId(String areaId) {
		if (ProvinceIndicatorConstant.NATION_AREA_ID.equals(areaId)) {
			return null;
		}
		// 省级
		if ("00".equals(areaId.substring(2, 4))) {
			return Lang.array(1, 5);
		}
		// 市级
		if ("00".equals(areaId.substring(4, 6))) {
			return Lang.array(5, 6, 2);
		}
		return null;
	}

	protected String getAreaParentId(String areaId) {
		Criteria criParent = Cnd.cri();
		criParent.where().and("id", "=", areaId);
		Record area = dao.fetch("tbl_area", criParent);
		String pid = area.getString("parent_id");
		return pid;
	}
}
